/*
    rna_structure.h: Molecular Biology ++ Header file.
    Copyright (C) 2010  Jorge Eloy Alan Atala, FuDePAN

    This file is part of Biopp.

    Aso is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Biopp is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Biopp.  If not, see <http://www.gnu.org/licenses/>.

    NOTE: This file is in prototype stage, and is under active development.
*/

#ifndef RNA_STRUCTURE_H
#define RNA_STRUCTURE_H

#include <assert.h>
#include <vector>
#include <mili/mili.h>

namespace biopp
{

/**
 * Index position in a sequence
 */
typedef unsigned int SeqIndex;

class SecStructure
{
    std::vector<SeqIndex> structure;

    inline SeqIndex unpaired_value() const
    {
        return structure.size();
    }

    bool circular;
public:
    SecStructure() : circular(false) {}

    SecStructure(const SecStructure& other_structure) : structure(other_structure.structure), circular(false) {}

    SecStructure(SeqIndex size)
    {
        set_sequence_size(size);
    }

    void pair(SeqIndex, SeqIndex);
    void unpair(SeqIndex);
    void set_sequence_size(SeqIndex size);
    SeqIndex paired_with(SeqIndex idx) const;

    SeqIndex get_next(SeqIndex i) const;
    SeqIndex get_prev(SeqIndex i) const;

    inline bool is_paired(SeqIndex idx) const
    {
        return structure.at(idx) != unpaired_value();
    }

    inline size_t pair_count() const
    {
        size_t paired = 0;
        for (SeqIndex i = 0; i < structure.size(); ++i)
        {
            if (is_paired(i))
                paired++;
        }
        return paired / 2;
    }

    inline size_t size() const
    {
        return structure.size();
    }

    void set_circular(bool is_circular = true)
    {
        circular = is_circular;
    }

    void set_linear(bool is_linear = false)
    {
        circular = !is_linear;
    }

    bool is_circular() const
    {
        return circular;
    }

    bool is_linear() const
    {
        return !circular;
    }

    void clear()
    {
        structure.clear();
    }
};

class SecStructureExceptionRoot {};

DEFINE_SPECIFIC_EXCEPTION_TEXT(InvalidStructureException, SecStructureExceptionRoot, "Invalid structure");

}
#endif
